#include "tut/tut.hpp"
#include "Basic1_Enum.hpp"
#include <typeinfo>

namespace tut
{
  struct Basic1_Enum_testdata{};

  typedef test_group<Basic1_Enum_testdata> Basic1_Enum_testgroup;
  typedef Basic1_Enum_testgroup::object Basic1_Enum_testobj;
  
  // instantiate
  Basic1_Enum_testgroup Basic1_Enum_group("Testing the generated Basic1_Enum class");


  template<> template<> void Basic1_Enum_testobj::
  test<1>()
  {
    set_test_name("default constructed object is invalid by default");
    Basic1_Enum basic;
    ensure(basic == Basic1_Enum::INVALID_);

    // proper string type?
    ensure(typeid(Basic1_Enum::string_type) == typeid(std::string));
  }

  template<> template<> void Basic1_Enum_testobj::
  test<2>()
  {
    set_test_name("Has proper member enumerators");

    ensure_equals("a", Basic1_Enum::a.value(), Basic1_Enum::raw::a);
    ensure_equals("b", Basic1_Enum::b.value(), Basic1_Enum::raw::b);
    ensure_equals("c", Basic1_Enum::c.value(), Basic1_Enum::raw::c);
    ensure_equals("i", Basic1_Enum::INVALID_.value(), Basic1_Enum::raw::INVALID_);
  }

  template<> template<> void Basic1_Enum_testobj::
  test<3>()
  {
    set_test_name("copy ctor");
    Basic1_Enum a(Basic1_Enum::a);
    Basic1_Enum b(Basic1_Enum::b);
    Basic1_Enum c(Basic1_Enum::c);
    Basic1_Enum i(Basic1_Enum::INVALID_);

    ensure_equals("a", a, Basic1_Enum::a);
    ensure_equals("b", b, Basic1_Enum::b);
    ensure_equals("c", c, Basic1_Enum::c);
    ensure_equals("i", i, Basic1_Enum::INVALID_);
  }

  template<> template<> void Basic1_Enum_testobj::
  test<4>()
  {
    set_test_name("raw enum ctor");
    Basic1_Enum a(Basic1_Enum::raw::a);
    Basic1_Enum b(Basic1_Enum::raw::b);
    Basic1_Enum c(Basic1_Enum::raw::c);
    Basic1_Enum i(Basic1_Enum::raw::INVALID_);

    ensure_equals("a", a, Basic1_Enum::a);
    ensure_equals("b", b, Basic1_Enum::b);
    ensure_equals("c", c, Basic1_Enum::c);
    ensure_equals("i", i, Basic1_Enum::INVALID_);
  }

  template<> template<> void Basic1_Enum_testobj::
  test<5>()
  {
    set_test_name("copy operator=");
    Basic1_Enum a;
    Basic1_Enum b;
    Basic1_Enum c;
    Basic1_Enum i;

    a = Basic1_Enum::a;
    b = Basic1_Enum::b;
    c = Basic1_Enum::c;
    i = Basic1_Enum::INVALID_;

    ensure_equals("a", a, Basic1_Enum::a);
    ensure_equals("b", b, Basic1_Enum::b);
    ensure_equals("c", c, Basic1_Enum::c);
    ensure_equals("i", i, Basic1_Enum::INVALID_);
  }    

  template<> template<> void Basic1_Enum_testobj::
  test<6>()
  {
    set_test_name("raw operator=");
    Basic1_Enum a;
    Basic1_Enum b;
    Basic1_Enum c;
    Basic1_Enum i;

    a = Basic1_Enum::raw::a;
    b = Basic1_Enum::raw::b;
    c = Basic1_Enum::raw::c;
    i = Basic1_Enum::raw::INVALID_;

    ensure_equals("a", a, Basic1_Enum::a);
    ensure_equals("b", b, Basic1_Enum::b);
    ensure_equals("c", c, Basic1_Enum::c);
    ensure_equals("i", i, Basic1_Enum::INVALID_);
  }    

  template<> template<> void Basic1_Enum_testobj::
  test<7>()
  {
    set_test_name("operator==");

    // enumgen/enumgen comps
    ensure("a1", Basic1_Enum::a == Basic1_Enum::a);
    ensure("b1", Basic1_Enum::b == Basic1_Enum::b);
    ensure("c1", Basic1_Enum::c == Basic1_Enum::c);
    ensure("i1", Basic1_Enum::INVALID_ == Basic1_Enum::INVALID_);

    // raw value tests
    ensure("a2", Basic1_Enum::a == Basic1_Enum::raw::a);
    ensure("b2", Basic1_Enum::b == Basic1_Enum::raw::b);
    ensure("c2", Basic1_Enum::c == Basic1_Enum::raw::c);
    ensure("i2", Basic1_Enum::INVALID_ == Basic1_Enum::raw::INVALID_);

    // symmetry
    ensure("a3", Basic1_Enum::raw::a == Basic1_Enum::a);
    ensure("b3", Basic1_Enum::raw::b == Basic1_Enum::b);
    ensure("c3", Basic1_Enum::raw::c == Basic1_Enum::c);
    ensure("i3", Basic1_Enum::raw::INVALID_ == Basic1_Enum::INVALID_);
  }

  template<> template<> void Basic1_Enum_testobj::
  test<8>()
  {
    set_test_name("operator!=");
    // enumgen/enumgen comps
    ensure("a1", Basic1_Enum::a != Basic1_Enum::b);
    ensure("a2", Basic1_Enum::a != Basic1_Enum::c);
    ensure("a3", Basic1_Enum::a != Basic1_Enum::INVALID_);
    ensure("a1", Basic1_Enum::a != Basic1_Enum::raw::b);
    ensure("a2", Basic1_Enum::a != Basic1_Enum::raw::c);
    ensure("a3", Basic1_Enum::a != Basic1_Enum::raw::INVALID_);

    ensure("b1", Basic1_Enum::b != Basic1_Enum::a);
    ensure("b2", Basic1_Enum::b != Basic1_Enum::c);
    ensure("b3", Basic1_Enum::b != Basic1_Enum::INVALID_);
    ensure("b1", Basic1_Enum::b != Basic1_Enum::raw::a);
    ensure("b2", Basic1_Enum::b != Basic1_Enum::raw::c);
    ensure("b3", Basic1_Enum::b != Basic1_Enum::raw::INVALID_);

    ensure("c1", Basic1_Enum::c != Basic1_Enum::a);
    ensure("c2", Basic1_Enum::c != Basic1_Enum::b);
    ensure("c3", Basic1_Enum::c != Basic1_Enum::INVALID_);
    ensure("c1", Basic1_Enum::c != Basic1_Enum::raw::a);
    ensure("c2", Basic1_Enum::c != Basic1_Enum::raw::b);
    ensure("c3", Basic1_Enum::c != Basic1_Enum::raw::INVALID_);

  }

  template<> template<> void Basic1_Enum_testobj::
  test<9>()
  {
    set_test_name("underlying value extractors");

    ensure_equals("a1", Basic1_Enum::a.value(), Basic1_Enum::raw::a);
    ensure_equals("b1", Basic1_Enum::b.value(), Basic1_Enum::raw::b);
    ensure_equals("c1", Basic1_Enum::c.value(), Basic1_Enum::raw::c);
    ensure_equals("i1", Basic1_Enum::INVALID_.value(), Basic1_Enum::raw::INVALID_);

    ensure_equals("a2", Basic1_Enum::a.as_long(), Basic1_Enum::raw::a);
    ensure_equals("b2", Basic1_Enum::b.as_long(), Basic1_Enum::raw::b);
    ensure_equals("c2", Basic1_Enum::c.as_long(), Basic1_Enum::raw::c);
    ensure_equals("i2", Basic1_Enum::INVALID_.as_long(), Basic1_Enum::raw::INVALID_);

    ensure_equals("a3", Basic1_Enum::a.as_long(), 0L);
    ensure_equals("b3", Basic1_Enum::b.as_long(), 1L);
    ensure_equals("c3", Basic1_Enum::c.as_long(), 2L);
    ensure_equals("i3", Basic1_Enum::INVALID_.as_long(), 3L);

    ensure_equals("a4", Basic1_Enum::a.value(), Basic1_Enum::a.as_long());
    ensure_equals("b4", Basic1_Enum::b.value(), Basic1_Enum::b.as_long());
    ensure_equals("c4", Basic1_Enum::c.value(), Basic1_Enum::c.as_long());
    ensure_equals("i5", Basic1_Enum::INVALID_.value(), Basic1_Enum::INVALID_.as_long());
  }


  template<> template<> void Basic1_Enum_testobj::
  test<10>()
  {
    set_test_name("underlying value setters");
    
    Basic1_Enum a;
    Basic1_Enum b;
    Basic1_Enum c;
    Basic1_Enum i1;
    Basic1_Enum i2;
    Basic1_Enum i3;

    // setting raw values to objects
    a.set_value_checked(Basic1_Enum::raw::a);
    b.set_value_checked(Basic1_Enum::raw::b);
    c.set_value_checked(Basic1_Enum::raw::c);
    i1.set_value_checked(Basic1_Enum::raw::INVALID_);
    i2.set_value_checked(static_cast<Basic1_Enum::raw::enum_type>(257)); 
    i3.set_value_checked(static_cast<Basic1_Enum::raw::enum_type>(-1)); 

    ensure_equals("a", a, Basic1_Enum::a);
    ensure_equals("b", b, Basic1_Enum::b);
    ensure_equals("c", c, Basic1_Enum::c);
    ensure_equals("i1", i1, Basic1_Enum::INVALID_);
    ensure_equals("i2", i2, Basic1_Enum::INVALID_);
    ensure_equals("i3", i3, Basic1_Enum::INVALID_);

    Basic1_Enum a2;
    Basic1_Enum b2;
    Basic1_Enum c2;

    // setting "long int" to objects
    a2.set_value_checked(0);
    b2.set_value_checked(1);
    c2.set_value_checked(2);
    i1.set_value_checked(3);
    i2.set_value_checked(-1);
    i3.set_value_checked(257);

    ensure_equals("a", a, Basic1_Enum::a);
    ensure_equals("b", b, Basic1_Enum::b);
    ensure_equals("c", c, Basic1_Enum::c);
    ensure_equals("i1", i1, Basic1_Enum::INVALID_);
    ensure_equals("i2", i2, Basic1_Enum::INVALID_);
    ensure_equals("i3", i3, Basic1_Enum::INVALID_);
  }

  template<> template<> void Basic1_Enum_testobj::
  test<11>()
  {
    set_test_name("string name() extractors");
    
    // converting an enumgen object to a string returns the
    // primary name.  If no primary name is explicitly set,
    // then it uses the spelling of the enumerator itself.
    ensure_equals("a.name()", Basic1_Enum::a.name(), "a");
    ensure_equals("b.name()", Basic1_Enum::b.name(), "b");
    ensure_equals("c.name()", Basic1_Enum::c.name(), "c");
    ensure_equals("INVALID_.name()", Basic1_Enum::INVALID_.name(), "INVALID_");
  }

  template<> template<> void Basic1_Enum_testobj::
  test<12>()
  {
    set_test_name("invalid query");
    ensure("a", !Basic1_Enum::a.invalid());
    ensure("b", !Basic1_Enum::b.invalid());
    ensure("c", !Basic1_Enum::c.invalid());
    ensure("i", Basic1_Enum::INVALID_.invalid());

    // default constructed
    ensure("default-constructed", Basic1_Enum().invalid());
  }

  template<> template<> void Basic1_Enum_testobj::
  test<13>()
  {
    set_test_name("name iterators");

    // this iterates over the names of enumerators.  That
    // is, for each name there should be a corresponding
    // static member of type Basic1_Enum with the same
    // spelling, representing an instance of this enum
    // object. 
    Basic1_Enum::const_name_iterator
        cur = Basic1_Enum::begin_name(),
        end = Basic1_Enum::end_name();

    ensure("begin,end", cur != end);
    ensure_equals("a", *cur, "a");
    ++cur;
    ensure("not-end 1", cur != end);
    ensure_equals("b", *cur, "b");    
    ++cur;
    ensure("not-end 2", cur != end);
    ensure_equals("c", *cur, "c");
    ++cur;
    ensure("not-end 3", cur != end);
    ensure_equals("INVALID_", *cur, "INVALID_");    
    ++cur;
    ensure("at-end 6", cur == end);
  }

  template<> template<> void Basic1_Enum_testobj::
  test<14>()
  {
    set_test_name("value iterators");

    // this iterates only over the object values
    Basic1_Enum::const_value_iterator
        cur = Basic1_Enum::begin_value(),
        end = Basic1_Enum::end_value();

    ensure("not-at-end 0", cur != end);

    ensure_equals("a", *cur, Basic1_Enum::a);
    ++cur;
    ensure("not-at-end 1", cur != end);
    ensure_equals("b", *cur, Basic1_Enum::b);
    ++cur;
    ensure("not-at-end 2", cur != end);
    ensure_equals("c", *cur, Basic1_Enum::c);
    ++cur;
    ensure("at-end", cur == end);
  }

  template<> template<> void Basic1_Enum_testobj::
  test<15>()
  {
    set_test_name("alias iterators");

    // test aliases for "a"
    Basic1_Enum:: const_name_iterator cur, end;

    cur = Basic1_Enum::a.begin_alias();
    end = Basic1_Enum::a.end_alias();
    ensure("a has no aliases", cur == end);

    // test aliases for "b"
    cur = Basic1_Enum::b.begin_alias();
    end = Basic1_Enum::b.end_alias();
    ensure("b has no aliases", cur == end);

    cur = Basic1_Enum::c.begin_alias();
    end = Basic1_Enum::c.end_alias();
    ensure("c has no aliases", cur == end);

    cur = Basic1_Enum::INVALID_.begin_alias();
    end = Basic1_Enum::INVALID_.end_alias();
    ensure("INVALID_ has no aliases", cur == end);
  }

  template<> template<> void Basic1_Enum_testobj::
  test<16>()
  {
    set_test_name("contains duplicates");
    ensure(Basic1_Enum::contains_duplicates() == false);
  }


  template<> template<> void Basic1_Enum_testobj::
  test<17>()
  {
    set_test_name("name_to_value");

    ensure_equals("a", Basic1_Enum::name_to_value("a"), Basic1_Enum::a);
    ensure_equals("b", Basic1_Enum::name_to_value("b"), Basic1_Enum::b);
    ensure_equals("c", Basic1_Enum::name_to_value("c"), Basic1_Enum::c);
    ensure_equals("invalid", Basic1_Enum::name_to_value("INVALID_"), Basic1_Enum::INVALID_);
  }


  template<> template<> void Basic1_Enum_testobj::
  test<18>()
  {
    set_test_name("value_to_name");

    ensure_equals("a->'a'", "a", Basic1_Enum::value_to_name(Basic1_Enum::a));
    ensure_equals("b->'b'", "b", Basic1_Enum::value_to_name(Basic1_Enum::b));
    ensure_equals("c->'c'", "c", Basic1_Enum::value_to_name(Basic1_Enum::c));
    ensure_equals("INVALID_->INVALID_", "INVALID_", Basic1_Enum::value_to_name(Basic1_Enum::INVALID_));
  }



  bool stream_test(Basic1_Enum val)
  {
    ensure(!val.invalid());

    std::stringstream oss;
    oss << val;
    Basic1_Enum newval;
    ensure(newval.invalid());
    oss >> newval;

    ensure_equals(val.name().c_str(), newval, val);
  }


  template<> template<> void Basic1_Enum_testobj::
  test<19>()
  {
    set_test_name("iostream ops");
    stream_test(Basic1_Enum::a);
    stream_test(Basic1_Enum::b);
    stream_test(Basic1_Enum::c);
  }

} // tut
 
